home *** CD-ROM | disk | FTP | other *** search
/ OpenGL Superbible (2nd Edition) / OpenGL SuperBible e2.iso / tools / GLUT-3.7 / LIB / GLE / EXTRUDE.C < prev    next >
Encoding:
C/C++ Source or Header  |  1998-08-12  |  25.4 KB  |  788 lines

  1.  
  2. /*
  3.  * MODULE: extrude.c
  4.  *
  5.  * FUNCTION:
  6.  * Provides  code for the cylinder, cone and extrusion routines. 
  7.  * The cylinders/cones/etc. are built on top of general purpose
  8.  * extrusions. The code that handles the general purpose extrusions 
  9.  * is in other modules.
  10.  * 
  11.  * AUTHOR:
  12.  * written by Linas Vepstas August/September 1991
  13.  * added polycone, February 1993
  14.  */
  15.  
  16. #include <stdlib.h>
  17. #include <math.h>
  18. #include <string.h>    /* for the memcpy() subroutine */
  19. #include <GL/tube.h>
  20. #include "gutil.h"
  21. #include "vvector.h"
  22. #include "tube_gc.h"
  23. #include "extrude.h"
  24. #include "intersect.h"
  25.  
  26. /* ============================================================ */
  27. /* The routine below  determines the type of join style that will be
  28.  * used for tubing. */
  29.  
  30. void gleSetJoinStyle (int style) 
  31. {
  32.    INIT_GC();
  33.    extrusion_join_style = style;
  34. }
  35.  
  36. int gleGetJoinStyle (void)
  37. {
  38.    INIT_GC();
  39.    return (extrusion_join_style);
  40. }
  41.  
  42. /* ============================================================ */
  43. /*
  44.  * draw a general purpose extrusion 
  45.  */
  46.  
  47. void gleSuperExtrusion (int ncp,               /* number of contour points */
  48.                 gleDouble contour[][2],    /* 2D contour */
  49.                 gleDouble cont_normal[][2], /* 2D contour normals */
  50.                 gleDouble up[3],           /* up vector for contour */
  51.                 int npoints,           /* numpoints in poly-line */
  52.                 gleDouble point_array[][3],        /* polyline */
  53.                 float color_array[][3],        /* color of polyline */
  54.                 gleDouble xform_array[][2][3])   /* 2D contour xforms */
  55. {   
  56.    INIT_GC();
  57.    _gle_gc -> ncp = ncp;
  58.    _gle_gc -> contour = contour;
  59.    _gle_gc -> cont_normal = cont_normal;
  60.    _gle_gc -> up = up;
  61.    _gle_gc -> npoints = npoints;
  62.    _gle_gc -> point_array = point_array;
  63.    _gle_gc -> color_array = color_array;
  64.    _gle_gc -> xform_array = xform_array;
  65.  
  66.    switch (__TUBE_STYLE) {
  67.       case TUBE_JN_RAW:
  68.          (void) extrusion_raw_join (ncp, contour, cont_normal, up,
  69.                                     npoints,
  70.                                     point_array, color_array,
  71.                                     xform_array);
  72.          break;
  73.  
  74.       case TUBE_JN_ANGLE:
  75.          (void) extrusion_angle_join (ncp, contour, cont_normal, up,
  76.                                     npoints,
  77.                                     point_array, color_array,
  78.                                     xform_array);
  79.          break;
  80.  
  81.       case TUBE_JN_CUT:
  82.       case TUBE_JN_ROUND:
  83.          /* This routine used for both cut and round styles */
  84.          (void) extrusion_round_or_cut_join (ncp, contour, cont_normal, up,
  85.                                     npoints,
  86.                                     point_array, color_array,
  87.                                     xform_array);
  88.          break;
  89.  
  90.       default:
  91.          break;
  92.    }
  93. }
  94.  
  95. /* ============================================================ */
  96.  
  97. void gleExtrusion (int ncp,               /* number of contour points */
  98.                 gleDouble contour[][2],    /* 2D contour */
  99.                 gleDouble cont_normal[][2], /* 2D contour normals */
  100.                 gleDouble up[3],           /* up vector for contour */
  101.                 int npoints,           /* numpoints in poly-line */
  102.                 gleDouble point_array[][3],        /* polyline */
  103.                 float color_array[][3])        /* color of polyline */
  104. {   
  105.    gleSuperExtrusion (ncp, contour, cont_normal, up,
  106.                     npoints,
  107.                     point_array, color_array,
  108.                     NULL);
  109. }
  110.  
  111. /* ============================================================ */
  112.  
  113. /* should really make this an adaptive algorithm ... */
  114. static int __gleSlices = 20;
  115.  
  116. int
  117. gleGetNumSlices(void)
  118. {
  119.   return __gleSlices;
  120. }
  121.  
  122. void
  123. gleSetNumSlices(int slices)
  124. {
  125.   __gleSlices = slices;
  126. }
  127.  
  128. void gen_polycone (int npoints,
  129.                gleDouble point_array[][3],
  130.                float color_array[][3],
  131.                gleDouble radius,
  132.                gleDouble xform_array[][2][3])
  133. {
  134.    int saved_style;
  135.    glePoint *circle = (glePoint*) malloc(sizeof(glePoint)*2*__gleSlices);
  136.    glePoint *norm = &circle[__gleSlices];
  137.    double c, s;
  138.    int i;
  139.    double v21[3];
  140.    double len;
  141.    gleDouble up[3];
  142.  
  143.    INIT_GC();
  144.  
  145.    /* this if statement forces this routine into double-duty for
  146.     * both the polycone and the polycylinder routines */
  147.    if (xform_array != NULL) radius = 1.0;
  148.  
  149.    s = sin (2.0*M_PI/ ((double) __gleSlices));
  150.    c = cos (2.0*M_PI/ ((double) __gleSlices));
  151.  
  152.    norm [0][0] = 1.0;
  153.    norm [0][1] = 0.0;
  154.    circle [0][0] = radius;
  155.    circle [0][1] = 0.0;
  156.  
  157.    /* draw a norm using recursion relations */
  158.    for (i=1; i<__gleSlices; i++) {
  159.       norm [i][0] = norm[i-1][0] * c - norm[i-1][1] * s;
  160.       norm [i][1] = norm[i-1][0] * s + norm[i-1][1] * c;
  161.       circle [i][0] = radius * norm[i][0];
  162.       circle [i][1] = radius * norm[i][1];
  163.    }
  164.  
  165.    /* avoid degenerate vectors */
  166.    /* first, find a non-zero length segment */
  167.    i=0;
  168.    FIND_NON_DEGENERATE_POINT(i,npoints,len,v21,point_array)
  169.    if (i == npoints) return;
  170.  
  171.    /* next, check to see if this segment lies along x-axis */
  172.    if ((v21[0] == 0.0) && (v21[2] == 0.0)) {
  173.       up[0] = up[1] = up[2] = 1.0;
  174.    } else {
  175.       up[0] = up[2] = 0.0;
  176.       up[1] = 1.0;
  177.    }
  178.  
  179.    /* save the current join style */
  180.    saved_style = extrusion_join_style;
  181.    extrusion_join_style |= TUBE_CONTOUR_CLOSED;
  182.  
  183.    /* if lighting is not turned on, don't send normals.  
  184.     * MMODE is a good indicator of whether lighting is active */
  185.    if (!__IS_LIGHTING_ON) {
  186.        gleSuperExtrusion (__gleSlices, circle, NULL, up,
  187.                      npoints, point_array, color_array,
  188.                      xform_array);
  189.    } else {
  190.        gleSuperExtrusion (__gleSlices, circle, norm, up,
  191.                      npoints, point_array, color_array,
  192.                      xform_array);
  193.    }
  194.    
  195.    /* restore the join style */
  196.    extrusion_join_style = saved_style;
  197.  
  198.    free(circle);
  199. }
  200.  
  201. /* ============================================================ */
  202.  
  203. void glePolyCylinder (int npoints,
  204.                    gleDouble point_array[][3],
  205.                    float color_array[][3],
  206.                    gleDouble radius)
  207. {
  208.    gen_polycone (npoints, point_array, color_array, radius, NULL);
  209. }
  210.  
  211. /* ============================================================ */
  212.  
  213. void glePolyCone (int npoints,
  214.                gleDouble point_array[][3],
  215.                float color_array[][3],
  216.                gleDouble radius_array[])
  217. {
  218.    gleAffine * xforms;
  219.    int j;
  220.  
  221.    /* build 2D affine matrices from radius array */
  222.    xforms = (gleAffine *) malloc (npoints * sizeof(gleAffine));
  223.    for (j=0; j<npoints; j++) {
  224.       AVAL(xforms,j,0,0) = radius_array[j];
  225.       AVAL(xforms,j,0,1) = 0.0;
  226.       AVAL(xforms,j,0,2) = 0.0;
  227.       AVAL(xforms,j,1,0) = 0.0;
  228.       AVAL(xforms,j,1,1) = radius_array[j];
  229.       AVAL(xforms,j,1,2) = 0.0;
  230.    }
  231.  
  232.    gen_polycone (npoints, point_array, color_array, 1.0, xforms);
  233.  
  234.    free (xforms);
  235. }
  236.  
  237. /* ============================================================ */
  238.  
  239. void gleTwistExtrusion (int ncp,         /* number of contour points */
  240.                 gleDouble contour[][2],    /* 2D contour */
  241.                 gleDouble cont_normal[][2], /* 2D contour normals */
  242.                 gleDouble up[3],           /* up vector for contour */
  243.                 int npoints,           /* numpoints in poly-line */
  244.                 gleDouble point_array[][3],        /* polyline */
  245.                 float color_array[][3],        /* color of polyline */
  246.                 gleDouble twist_array[])   /* countour twists (in degrees) */
  247.  
  248. {
  249.    int j;
  250.    double angle;
  251.    double si, co;
  252.  
  253.    gleAffine *xforms;
  254.  
  255.    /* build 2D affine matrices from radius array */
  256.    xforms = (gleAffine *) malloc (npoints * sizeof(gleAffine));
  257.  
  258.    for (j=0; j<npoints; j++) {
  259.       angle = (M_PI/180.0) * twist_array[j];
  260.       si = sin (angle);
  261.       co = cos (angle);
  262.       AVAL(xforms,j,0,0) = co;
  263.       AVAL(xforms,j,0,1) = -si;
  264.       AVAL(xforms,j,0,2) = 0.0;
  265.       AVAL(xforms,j,1,0) = si;
  266.       AVAL(xforms,j,1,1) = co;
  267.       AVAL(xforms,j,1,2) = 0.0;
  268.    }
  269.  
  270.    gleSuperExtrusion (ncp,               /* number of contour points */
  271.                 contour,    /* 2D contour */
  272.                 cont_normal, /* 2D contour normals */
  273.                 up,           /* up vector for contour */
  274.                 npoints,           /* numpoints in poly-line */
  275.                 point_array,        /* polyline */
  276.                 color_array,        /* color of polyline */
  277.                 xforms);
  278.  
  279.    free (xforms);
  280. }
  281.  
  282. /* ============================================================ */
  283. /* 
  284.  * The spiral primitive forms the basis for the helicoid primitive.
  285.  *
  286.  * Note that this primitive sweeps a contour along a helical path.
  287.  * The algorithm assumes that the path is embedded in Euclidean space,
  288.  * and uses parallel transport along the path.  Parallel transport
  289.  * provides the simplest mathematical model for moving a coordinate 
  290.  * system along a curved path, but some of the effects of doing so 
  291.  * may prove to be surprising to one uninitiated to the concept.
  292.  *
  293.  * Thus, we provide another, related, algorithm below, called "lathe"
  294.  * which introduces a torsion component along the path, correcting for
  295.  * the rotation induced by the helical path.
  296.  *
  297.  * If the above sounds like gobldy-gook to you, you may want to brush 
  298.  * up on differential geometry. Recommend Spivak, Differential Geometry,
  299.  * Volume 1, pages xx-xx.
  300.  */
  301.  
  302. void gleSpiral (int ncp,               /* number of contour points */
  303.              gleDouble contour[][2],    /* 2D contour */
  304.              gleDouble cont_normal[][2], /* 2D contour normals */
  305.              gleDouble up[3],           /* up vector for contour */
  306.              gleDouble startRadius,
  307.              gleDouble drdTheta,        /* change in radius per revolution */
  308.              gleDouble startZ,
  309.              gleDouble dzdTheta,        /* change in Z per revolution */
  310.              gleDouble startXform[2][3],
  311.              gleDouble dXformdTheta[2][3], /* tangent change xform per revolution */
  312.              gleDouble startTheta,          /* start angle, in degrees */
  313.              gleDouble sweepTheta)        /* sweep angle, in degrees */
  314. {
  315.    int npoints;
  316.    gleDouble deltaAngle;
  317.    char * mem_anchor;
  318.    gleDouble *pts;
  319.    gleAffine *xforms;
  320.    double delta;
  321.  
  322.    int saved_style;
  323.    double ccurr, scurr;
  324.    double cprev, sprev;
  325.    double cdelta, sdelta;
  326.    double mA[2][2], mB[2][2];
  327.    double run[2][2];
  328.    double deltaTrans[2];
  329.    double trans[2];
  330.    int i;
  331.  
  332.    /* allocate sufficient memory to store path */
  333.    npoints = (int) ((((double) __gleSlices) /360.0) * fabs(sweepTheta)) + 4;
  334.  
  335.    if (startXform == NULL) {
  336.       mem_anchor = malloc (3*npoints * sizeof (gleDouble));
  337.       pts = (gleDouble *) mem_anchor;
  338.       xforms = NULL;
  339.    } else {
  340.       mem_anchor = malloc ((1+2)* 3*npoints * sizeof (gleDouble));
  341.       pts = (gleDouble *) mem_anchor;
  342.       xforms = (gleAffine *) (pts + 3*npoints);
  343.    }
  344.  
  345.    /* compute delta angle based on number of points */
  346.    deltaAngle = (M_PI / 180.0) * sweepTheta / ((gleDouble) (npoints-3));
  347.    startTheta *= M_PI / 180.0;
  348.    startTheta -= deltaAngle;
  349.  
  350.    /* initialize factors */
  351.    cprev = cos ((double) startTheta);
  352.    sprev = sin ((double) startTheta);
  353.  
  354.    cdelta = cos ((double) deltaAngle);
  355.    sdelta = sin ((double) deltaAngle);
  356.  
  357.    /* renormalize differential factors */
  358.    delta = deltaAngle / (2.0 * M_PI);
  359.    dzdTheta *= delta;
  360.    drdTheta *= delta;
  361.  
  362.    /* remember, the first point is hidden, so back-step */
  363.    startZ -=  dzdTheta;
  364.    startRadius -=  drdTheta;
  365.  
  366.    /* draw spiral path using recursion relations for sine, cosine */
  367.    for (i=0; i<npoints; i++) {
  368.       pts [3*i] =  startRadius * cprev;
  369.       pts [3*i+1] =  startRadius * sprev;
  370.       pts [3*i+2] = (gleDouble) startZ;
  371.  
  372.       startZ +=  dzdTheta;
  373.       startRadius +=  drdTheta;
  374.       ccurr = cprev * cdelta - sprev * sdelta;
  375.       scurr = cprev * sdelta + sprev * cdelta;
  376.       cprev = ccurr;
  377.       sprev = scurr;
  378.    }
  379.  
  380.    /* If there is a deformation matrix specified, then a deformation
  381.     * path must be generated also */
  382.    if (startXform != NULL) {
  383.       if (dXformdTheta == NULL) {
  384.          for (i=0; i<npoints; i++) {
  385.             xforms[i][0][0] = startXform[0][0];
  386.             xforms[i][0][1] = startXform[0][1];
  387.             xforms[i][0][2] = startXform[0][2];
  388.             xforms[i][1][0] = startXform[1][0];
  389.             xforms[i][1][1] = startXform[1][1];
  390.             xforms[i][1][2] = startXform[1][2];
  391.          }
  392.       } else {
  393.          /* 
  394.           * if there is a differential matrix specified, treat it a 
  395.           * a tangent (algebraic, infinitessimal) matrix.  We need to
  396.           * project it into the group of real 2x2 matricies.  (Note that
  397.           * the specified matrix is affine.  We treat the translation 
  398.           * components linearly, and only treat the 2x2 submatrix as an 
  399.           * algebraic tangenet).
  400.           *
  401.           * For exponentiaition, we use the well known approx:
  402.           * exp(x) = lim (N->inf) (1+x/N) ** N
  403.           * and take N=32. 
  404.           */
  405.  
  406.          /* initialize translation and delta translation */
  407.          deltaTrans[0] = delta * dXformdTheta[0][2];
  408.          deltaTrans[1] = delta * dXformdTheta[1][2];
  409.          trans[0] = startXform[0][2];
  410.          trans[1] = startXform[1][2];
  411.    
  412.          /* prepare the tangent matrix */
  413.          delta /= 32.0;
  414.          mA[0][0] = 1.0 + delta * dXformdTheta[0][0];
  415.          mA[0][1] = delta * dXformdTheta[0][1];
  416.          mA[1][0] = delta * dXformdTheta[1][0];
  417.          mA[1][1] = 1.0 + delta * dXformdTheta[1][1];
  418.    
  419.          /* compute exponential of matrix */
  420.          MATRIX_PRODUCT_2X2 (mB, mA, mA);  /* squared */
  421.          MATRIX_PRODUCT_2X2 (mA, mB, mB);  /* 4th power */
  422.          MATRIX_PRODUCT_2X2 (mB, mA, mA);  /* 8th power */
  423.          MATRIX_PRODUCT_2X2 (mA, mB, mB);  /* 16th power */
  424.          MATRIX_PRODUCT_2X2 (mB, mA, mA);  /* 32nd power */
  425.    
  426.          /* initialize running matrix */
  427.          COPY_MATRIX_2X2 (run, startXform);
  428.    
  429.          /* remember, the first point is hidden -- load some, any 
  430.           * xform for the first point */
  431.          xforms[0][0][0] = startXform[0][0];
  432.          xforms[0][0][1] = startXform[0][1];
  433.          xforms[0][0][2] = startXform[0][2];
  434.          xforms[0][1][0] = startXform[1][0];
  435.          xforms[0][1][1] = startXform[1][1];
  436.          xforms[0][1][2] = startXform[1][2];
  437.  
  438.          for (i=1; i<npoints; i++) {
  439. #ifdef FUNKY_C
  440.             xforms[6*i] = run[0][0];
  441.             xforms[6*i+1] = run[0][1];
  442.             xforms[6*i+3] = run[1][0];
  443.             xforms[6*i+4] = run[1][1];
  444. #endif /* FUNKY_C */
  445.             xforms[i][0][0] = run[0][0];
  446.             xforms[i][0][1] = run[0][1];
  447.             xforms[i][1][0] = run[1][0];
  448.             xforms[i][1][1] = run[1][1];
  449.  
  450.             /* integrate to get exponential matrix */
  451.             /* (Note that the group action is a left-action --
  452.              * i.e. multiply on the left (not the right)) */
  453.             MATRIX_PRODUCT_2X2 (mA, mB, run);
  454.             COPY_MATRIX_2X2 (run, mA);
  455.          
  456. #ifdef FUNKY_C
  457.             xforms[6*i+2] = trans [0];
  458.             xforms[6*i+5] = trans [1];
  459. #endif /* FUNKY_C */
  460.             xforms[i][0][2] = trans [0];
  461.             xforms[i][1][2] = trans [1];
  462.             trans[0] += deltaTrans[0];
  463.             trans[1] += deltaTrans[1];
  464.  
  465.          }
  466.       }
  467.    }
  468.  
  469.    /* save the current join style */
  470.    saved_style = extrusion_join_style;
  471.  
  472.    /* Allow only angle joins (for performance reasons).
  473.     * The idea is that if the tesselation is fine enough, then an angle
  474.     * join should be sufficient to get the desired visual quality.  A 
  475.     * raw join would look terrible, an cut join would leave garbage 
  476.     * everywhere, and a round join will over-tesselate (and thus 
  477.     * should be avoided for performance reasons). 
  478.     */
  479.    extrusion_join_style  &= ~TUBE_JN_MASK; 
  480.    extrusion_join_style  |= TUBE_JN_ANGLE;
  481.  
  482.    gleSuperExtrusion (ncp, contour, cont_normal, up,
  483.                   npoints, (gleVector *) pts, NULL, xforms);
  484.  
  485.    /* restore the join style */
  486.    extrusion_join_style = saved_style;
  487.  
  488.    free (mem_anchor);
  489.  
  490. }
  491.  
  492.  
  493. /* ============================================================ */
  494. /* 
  495.  */
  496.  
  497. void gleLathe (int ncp,               /* number of contour points */
  498.              gleDouble contour[][2],    /* 2D contour */
  499.              gleDouble cont_normal[][2], /* 2D contour normals */
  500.              gleDouble up[3],           /* up vector for contour */
  501.              gleDouble startRadius,
  502.              gleDouble drdTheta,        /* change in radius per revolution */
  503.              gleDouble startZ,
  504.              gleDouble dzdTheta,        /* change in Z per revolution */
  505.              gleDouble startXform[2][3],
  506.              gleDouble dXformdTheta[2][3], /* tangent change xform per revln */
  507.              gleDouble startTheta,          /* start angle, in degrees */
  508.              gleDouble sweepTheta)        /* sweep angle, in degrees */
  509. {
  510.    gleDouble localup[3];
  511.    gleDouble len;
  512.    gleDouble trans[2];
  513.    gleDouble start[2][3], delt[2][3];
  514.  
  515.    /* Because the spiral always starts on the axis, and proceeds in the
  516.     * positive y direction, we can see that valid up-vectors must lie 
  517.     * in the x-z plane. Therefore, we make sure we have a valid up
  518.     * vector by projecting it onto the x-z plane, and normalizing. */
  519.    if (up[1] != 0.0) {
  520.       localup[0] = up[0];
  521.       localup[1] = 0.0;
  522.       localup[2] = up[2];
  523.       VEC_LENGTH (len, localup);
  524.       if (len != 0.0) {
  525.          len = 1.0/len;
  526.          localup[0] *= len;
  527.          localup[2] *= len;
  528.          VEC_SCALE (localup, len, localup);
  529.       } else {
  530.          /* invalid up vector was passed in */
  531.          localup[0] = 0.0;
  532.          localup[2] = 1.0;
  533.       }
  534.    } else {
  535.       VEC_COPY (localup, up);
  536.    }
  537.  
  538.    /* the dzdtheta derivative and the drdtheta derivative form a vector
  539.     * in the x-z plane.  dzdtheta is the z component, and drdtheta is 
  540.     * the x component.  We need to convert this vector into the local 
  541.     * coordinate system defined by the up vector.  We do this by 
  542.     * applying a 2D rotation matrix. 
  543.     */
  544.    trans[0] = localup[2] * drdTheta - localup[0] * dzdTheta;
  545.    trans[1] = localup[0] * drdTheta + localup[2] * dzdTheta;
  546.  
  547.    /* now, add this translation vector into the affine xform */
  548.    if (startXform != NULL) {
  549.       if (dXformdTheta != NULL) {
  550.          COPY_MATRIX_2X3 (delt, dXformdTheta);
  551.          delt[0][2] += trans[0];
  552.          delt[1][2] += trans[1];
  553.       } else {
  554.          /*Hmm- the transforms don't exist */
  555.  
  556.          delt[0][0] = 0.0;
  557.          delt[0][1] = 0.0;
  558.          delt[0][2] = trans[0];
  559.          delt[1][0] = 0.0;
  560.          delt[1][1] = 0.0;
  561.          delt[1][2] = trans[1];
  562.       }
  563.       gleSpiral (ncp, contour, cont_normal, up, 
  564.               startRadius, 0.0, startZ, 0.0,
  565.               startXform, delt,
  566.               startTheta, sweepTheta);
  567.  
  568.    } else {
  569.       /* Hmm- the transforms don't exist */
  570.       start[0][0] = 1.0;
  571.       start[0][1] = 0.0;
  572.       start[0][2] = 0.0;
  573.       start[1][0] = 0.0;
  574.       start[1][1] = 1.0;
  575.       start[1][2] = 0.0;
  576.  
  577.       delt[0][0] = 0.0;
  578.       delt[0][1] = 0.0;
  579.       delt[0][2] = trans[0];
  580.       delt[1][0] = 0.0;
  581.       delt[1][1] = 0.0;
  582.       delt[1][2] = trans[1];
  583.       gleSpiral (ncp, contour, cont_normal, up, 
  584.               startRadius, 0.0, startZ, 0.0,
  585.               start, delt,
  586.               startTheta, sweepTheta);
  587.    }
  588. }
  589.  
  590.  
  591. /* ============================================================ */
  592. /*
  593.  * Super-Helicoid primitive 
  594.  */
  595.  
  596. typedef void (*HelixCallback) (
  597.              int ncp,               
  598.              gleDouble contour[][2],
  599.              gleDouble cont_normal[][2],
  600.              gleDouble up[3],
  601.              gleDouble startRadius,
  602.              gleDouble drdTheta,
  603.              gleDouble startZ,
  604.              gleDouble dzdTheta,
  605.              gleDouble startXform[2][3],
  606.              gleDouble dXformdTheta[2][3],
  607.              gleDouble startTheta,
  608.              gleDouble sweepTheta);
  609.  
  610. void super_helix (gleDouble rToroid,
  611.              gleDouble startRadius,
  612.              gleDouble drdTheta,        /* change in radius per revolution */
  613.              gleDouble startZ,
  614.              gleDouble dzdTheta,        /* change in Z per revolution */
  615.              gleDouble startXform[2][3],
  616.              gleDouble dXformdTheta[2][3], /* tangent change xform per revol */
  617.              gleDouble startTheta,          /* start angle, in degrees */
  618.              gleDouble sweepTheta,        /* sweep angle, in degrees */
  619.          HelixCallback helix_callback)
  620. {
  621.  
  622.    int saved_style;
  623.    glePoint *circle = (glePoint*) malloc(sizeof(glePoint)*2*__gleSlices);
  624.    glePoint *norm = &circle[__gleSlices];
  625.    double c, s;
  626.    int i;
  627.    gleDouble up[3];
  628.  
  629.    /* initialize sine and cosine for circle recusrion equations */
  630.    s = sin (2.0*M_PI/ ((double) __gleSlices));
  631.    c = cos (2.0*M_PI/ ((double) __gleSlices));
  632.  
  633.    norm [0][0] = 1.0;
  634.    norm [0][1] = 0.0;
  635.    circle [0][0] = rToroid;
  636.    circle [0][1] = 0.0;
  637.  
  638.    /* draw a norm using recursion relations */
  639.    for (i=1; i<__gleSlices; i++) {
  640.       norm [i][0] = norm[i-1][0] * c - norm[i-1][1] * s;
  641.       norm [i][1] = norm[i-1][0] * s + norm[i-1][1] * c;
  642.       circle [i][0] = rToroid * norm[i][0];
  643.       circle [i][1] = rToroid * norm[i][1];
  644.    }
  645.  
  646.    /* make up vector point along x axis */
  647.    up[1] = up[2] = 0.0;
  648.    up[0] = 1.0;
  649.  
  650.    /* save the current join style */
  651.    saved_style = extrusion_join_style;
  652.    extrusion_join_style |= TUBE_CONTOUR_CLOSED;
  653.    extrusion_join_style |= TUBE_NORM_PATH_EDGE;
  654.  
  655.    /* if lighting is not turned on, don't send normals.  
  656.     * MMODE is a good indicator of whether lighting is active */
  657.    if (!__IS_LIGHTING_ON) {
  658.       (*helix_callback) (__gleSlices, circle, NULL, up,
  659.              startRadius,
  660.              drdTheta,
  661.              startZ,
  662.              dzdTheta,
  663.              startXform,
  664.              dXformdTheta,
  665.              startTheta,
  666.              sweepTheta);
  667.    } else {
  668.       (*helix_callback) (__gleSlices, circle, norm, up,
  669.              startRadius,
  670.              drdTheta,
  671.              startZ,
  672.              dzdTheta,
  673.              startXform,
  674.              dXformdTheta,
  675.              startTheta,
  676.              sweepTheta);
  677.    }
  678.    
  679.    /* restore the join style */
  680.    extrusion_join_style = saved_style;
  681.  
  682.    free(circle);
  683. }
  684.  
  685. /* ============================================================ */
  686. /*
  687.  * Helicoid primitive 
  688.  * Uses Parallel Transport to take a circular contour along a helical
  689.  * path.
  690.  */
  691.  
  692. void gleHelicoid (gleDouble rToroid,
  693.              gleDouble startRadius,
  694.              gleDouble drdTheta,        /* change in radius per revolution */
  695.              gleDouble startZ,
  696.              gleDouble dzdTheta,        /* change in Z per revolution */
  697.              gleDouble startXform[2][3],
  698.              gleDouble dXformdTheta[2][3], /* tangent change xform per revol */
  699.              gleDouble startTheta,          /* start angle, in degrees */
  700.              gleDouble sweepTheta)        /* sweep angle, in degrees */
  701. {
  702.    super_helix (rToroid,
  703.              startRadius,
  704.              drdTheta,        /* change in radius per revolution */
  705.              startZ,
  706.              dzdTheta,        /* change in Z per revolution */
  707.              startXform,
  708.              dXformdTheta, /* tangent change xform per revolution */
  709.              startTheta,          /* start angle, in degrees */
  710.              sweepTheta,       /* sweep angle, in degrees */
  711.              gleSpiral);
  712. }
  713.  
  714.  
  715. /* ============================================================ */
  716. /*
  717.  * Toroid primitive 
  718.  * Uses a helical coordinate system dislocation to take a circular 
  719.  * contour along a helical path.
  720.  */
  721.  
  722. void gleToroid (gleDouble rToroid,
  723.              gleDouble startRadius,
  724.              gleDouble drdTheta,        /* change in radius per revolution */
  725.              gleDouble startZ,
  726.              gleDouble dzdTheta,        /* change in Z per revolution */
  727.              gleDouble startXform[2][3],
  728.              gleDouble dXformdTheta[2][3], /* tangent change xform per revol */
  729.              gleDouble startTheta,          /* start angle, in degrees */
  730.              gleDouble sweepTheta)        /* sweep angle, in degrees */
  731. {
  732.    super_helix (rToroid,
  733.              startRadius,
  734.              drdTheta,        /* change in radius per revolution */
  735.              startZ,
  736.              dzdTheta,        /* change in Z per revolution */
  737.              startXform,
  738.              dXformdTheta, /* tangent change xform per revolution */
  739.              startTheta,          /* start angle, in degrees */
  740.              sweepTheta,       /* sweep angle, in degrees */
  741.              gleLathe);
  742. }
  743.  
  744. /* ============================================================ */
  745.  
  746. void gleScrew (int ncp, 
  747.                gleDouble contour[][2], 
  748.                gleDouble cont_normal[][2], 
  749.                gleDouble up[3],
  750.                gleDouble startz,
  751.                gleDouble endz,
  752.                gleDouble twist) 
  753. {
  754.    int i, numsegs;
  755.    gleVector * path; 
  756.    gleDouble *twarr;
  757.    gleDouble currz, delta; 
  758.    gleDouble currang, delang; 
  759.  
  760.    /* no segment should rotate more than 18 degrees */
  761.    numsegs = (int) fabs (twist / 18.0) + 4;
  762.  
  763.    /* malloc the extrusion array and the twist array */
  764.    path = (gleVector *) malloc (numsegs * sizeof (gleVector));
  765.    twarr = (gleDouble *) malloc (numsegs * sizeof (gleDouble));
  766.  
  767.    /* fill in the extrusion array and the twist array uniformly */
  768.    delta = (endz-startz) / ((gleDouble) (numsegs-3));
  769.    currz = startz-delta;
  770.    delang = twist / ((gleDouble) (numsegs-3));
  771.    currang = -delang;
  772.    for (i=0; i<numsegs; i++) {
  773.       path [i][0] = 0.0;
  774.       path [i][1] = 0.0;
  775.       path [i][2] = currz;
  776.       currz += delta;
  777.       twarr[i] = currang;
  778.       currang +=delang;
  779.    }
  780.  
  781.    gleTwistExtrusion (ncp, contour, cont_normal, up, numsegs, path, NULL, twarr);
  782.  
  783.    free (path);
  784.    free (twarr);
  785. }
  786.  
  787. /* ============================================================ */
  788.